"""
会议调度数据集生成工具

生成多样化的会议安排场景用于训练和评估
"""

import json
import random
import os
from typing import List, Dict


# 配置参数
DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
TIME_SLOTS = ['morning', 'afternoon', 'evening']

NAME_POOL = ['李明', '王芳', '陈静', '刘强', '赵敏', '张伟', '周娟', '吴杰', '郑勇', '孙丽']

TOPICS = [
    '产品规划会', '技术评审会', '季度总结会', '项目启动会',
    '需求讨论会', '设计评审会', '运营周会', '客户沟通会',
    '战略研讨会', '团队建设会', '培训分享会', '绩效面谈'
]


def generate_calendar_for_person(availability_rate: float = 0.6) -> Dict[str, Dict[str, str]]:
    """
    为一个人生成日程

    参数:
        availability_rate: 空闲时段的概率

    返回:
        日程字典 {day: {time_slot: status}}
    """
    calendar = {}
    for day in DAYS:
        calendar[day] = {}
        for slot in TIME_SLOTS:
            status = 'available' if random.random() < availability_rate else 'busy'
            calendar[day][slot] = status

    return calendar


def generate_historical_meetings(topic: str,
                                 num_weeks: int = 5,
                                 pattern_probability: float = 0.8) -> List[Dict]:
    """
    生成历史会议记录

    参数:
        topic: 会议主题
        num_weeks: 历史周数
        pattern_probability: 遵循模式的概率

    返回:
        历史会议列表
    """
    # 随机选择一个偏好时段作为模式
    pattern_day = random.choice(DAYS)
    pattern_slot = random.choice(TIME_SLOTS)

    meetings = []
    for week in range(-num_weeks, 0):
        # 按概率决定是否遵循模式
        if random.random() < pattern_probability:
            day, slot = pattern_day, pattern_slot
        else:
            day = random.choice(DAYS)
            slot = random.choice(TIME_SLOTS)

        meetings.append({
            'topic': topic,
            'week': week,
            'day': day,
            'time_slot': slot
        })

    return meetings


def generate_instance(difficulty: str = 'medium') -> Dict:
    """
    生成单个会议安排实例

    参数:
        difficulty: 难度等级
            - easy: 容易找到满足所有条件的时间
            - medium: 需要适度权衡
            - hard: 需要协商或放弃历史模式

    返回:
        实例字典
    """
    # 根据难度调整参数
    if difficulty == 'easy':
        num_people = random.randint(4, 6)
        num_required = 2
        availability_rate = 0.7  # 较高空闲率
        historical_pattern_prob = 0.9
    elif difficulty == 'medium':
        num_people = random.randint(5, 7)
        num_required = random.randint(2, 3)
        availability_rate = 0.6
        historical_pattern_prob = 0.8
    else:  # hard
        num_people = random.randint(6, 8)
        num_required = random.randint(3, 4)
        availability_rate = 0.5  # 较低空闲率
        historical_pattern_prob = 0.7

    # 随机选择人员
    selected_people = random.sample(NAME_POOL, min(num_people, len(NAME_POOL)))

    # 分配必选/可选
    required_attendees = selected_people[:num_required]
    optional_attendees = selected_people[num_required:]

    # 选择会议主题
    topic = random.choice(TOPICS)

    # 生成日程
    calendar_data = {}
    for person in selected_people:
        calendar_data[person] = generate_calendar_for_person(availability_rate)

    # 生成历史会议
    historical_meetings = generate_historical_meetings(topic, num_weeks=5, pattern_probability=historical_pattern_prob)

    # 对于hard难度，故意让必选人员在历史偏好时段部分不可用
    if difficulty == 'hard' and historical_meetings:
        # 找到历史模式
        pattern_counts = {}
        for meeting in historical_meetings:
            key = (meeting['day'], meeting['time_slot'])
            pattern_counts[key] = pattern_counts.get(key, 0) + 1

        if pattern_counts:
            pattern_day, pattern_slot = max(pattern_counts.items(), key=lambda x: x[1])[0]

            # 让至少一个必选人员在该时段不可用
            conflict_person = random.choice(required_attendees)
            calendar_data[conflict_person][pattern_day][pattern_slot] = 'busy'

    instance = {
        'meeting_topic': topic,
        'required_attendees': required_attendees,
        'optional_attendees': optional_attendees,
        'calendar_data': calendar_data,
        'historical_meetings': historical_meetings,
        'difficulty': difficulty
    }

    return instance


def generate_dataset(num_instances: int,
                    difficulty_distribution: Dict[str, float] = None,
                    output_path: str = None) -> List[Dict]:
    """
    生成数据集

    参数:
        num_instances: 实例数量
        difficulty_distribution: 难度分布，如 {'easy': 0.3, 'medium': 0.5, 'hard': 0.2}
        output_path: 输出文件路径（可选）

    返回:
        实例列表
    """
    if difficulty_distribution is None:
        difficulty_distribution = {'easy': 0.3, 'medium': 0.5, 'hard': 0.2}

    # 归一化分布
    total = sum(difficulty_distribution.values())
    difficulty_distribution = {k: v/total for k, v in difficulty_distribution.items()}

    # 计算每个难度的数量
    difficulty_counts = {}
    remaining = num_instances
    for difficulty, prob in difficulty_distribution.items():
        count = int(num_instances * prob)
        difficulty_counts[difficulty] = count
        remaining -= count

    # 分配剩余的到medium
    difficulty_counts['medium'] += remaining

    # 生成实例
    instances = []
    for difficulty, count in difficulty_counts.items():
        for _ in range(count):
            instance = generate_instance(difficulty)
            instances.append(instance)

    # 打乱顺序
    random.shuffle(instances)

    # 保存到文件
    if output_path:
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(instances, f, ensure_ascii=False, indent=2)
        print(f"数据集已保存到: {output_path}")
        print(f"总实例数: {len(instances)}")
        print(f"难度分布: {difficulty_counts}")

    return instances


def analyze_instance(instance: Dict) -> Dict:
    """
    分析实例的特征

    参数:
        instance: 实例字典

    返回:
        分析结果
    """
    analysis = {
        'meeting_topic': instance['meeting_topic'],
        'difficulty': instance.get('difficulty', 'unknown'),
        'num_required': len(instance['required_attendees']),
        'num_optional': len(instance['optional_attendees']),
        'num_total': len(instance['required_attendees']) + len(instance['optional_attendees']),
    }

    # 计算历史模式
    if instance['historical_meetings']:
        pattern_counts = {}
        for meeting in instance['historical_meetings']:
            key = (meeting['day'], meeting['time_slot'])
            pattern_counts[key] = pattern_counts.get(key, 0) + 1

        most_common = max(pattern_counts.items(), key=lambda x: x[1])
        analysis['historical_pattern'] = {
            'day': most_common[0][0],
            'time_slot': most_common[0][1],
            'frequency': most_common[1] / len(instance['historical_meetings'])
        }

    # 统计可用性
    total_slots = 0
    available_slots = 0

    for person in instance['required_attendees'] + instance['optional_attendees']:
        calendar = instance['calendar_data'][person]
        for day in DAYS:
            for slot in TIME_SLOTS:
                total_slots += 1
                if calendar[day][slot] == 'available':
                    available_slots += 1

    analysis['overall_availability_rate'] = available_slots / total_slots

    # 检查历史偏好时段的可用性
    if 'historical_pattern' in analysis:
        pattern_day = analysis['historical_pattern']['day']
        pattern_slot = analysis['historical_pattern']['time_slot']

        required_available_at_pattern = sum(
            1 for person in instance['required_attendees']
            if instance['calendar_data'][person][pattern_day][pattern_slot] == 'available'
        )

        analysis['required_available_at_historical_pattern'] = required_available_at_pattern
        analysis['required_total'] = len(instance['required_attendees'])

    return analysis


def print_dataset_statistics(dataset: List[Dict]):
    """打印数据集统计信息"""
    print("\n" + "="*80)
    print("数据集统计信息")
    print("="*80)

    print(f"\n总实例数: {len(dataset)}")

    # 难度分布
    difficulty_counts = {}
    for instance in dataset:
        difficulty = instance.get('difficulty', 'unknown')
        difficulty_counts[difficulty] = difficulty_counts.get(difficulty, 0) + 1

    print(f"\n难度分布:")
    for difficulty, count in sorted(difficulty_counts.items()):
        print(f"  {difficulty}: {count} ({count/len(dataset)*100:.1f}%)")

    # 主题分布
    topic_counts = {}
    for instance in dataset:
        topic = instance['meeting_topic']
        topic_counts[topic] = topic_counts.get(topic, 0) + 1

    print(f"\n会议主题分布 (前5):")
    for topic, count in sorted(topic_counts.items(), key=lambda x: x[1], reverse=True)[:5]:
        print(f"  {topic}: {count}")

    # 分析几个示例
    print(f"\n示例分析 (前3个实例):")
    for i, instance in enumerate(dataset[:3]):
        analysis = analyze_instance(instance)
        print(f"\n实例 {i+1}:")
        print(f"  主题: {analysis['meeting_topic']}")
        print(f"  难度: {analysis['difficulty']}")
        print(f"  人员: {analysis['num_required']}必选 + {analysis['num_optional']}可选")
        print(f"  整体空闲率: {analysis['overall_availability_rate']:.2%}")
        if 'historical_pattern' in analysis:
            hp = analysis['historical_pattern']
            print(f"  历史模式: {hp['day']}, {hp['time_slot']} (频率: {hp['frequency']:.1%})")
            if 'required_available_at_historical_pattern' in analysis:
                print(f"  历史时段必选人员可用: {analysis['required_available_at_historical_pattern']}/{analysis['required_total']}")


def main():
    """主函数：生成数据集"""
    print("智能会议安排系统 - 数据集生成工具\n")

    # 设置随机种子以便复现
    random.seed(42)

    # 生成训练集
    print("生成训练集...")
    train_dataset = generate_dataset(
        num_instances=100,
        difficulty_distribution={'easy': 0.3, 'medium': 0.5, 'hard': 0.2},
        output_path='data/meeting_scheduling/train_dataset.json'
    )

    # 生成验证集
    print("\n生成验证集...")
    random.seed(123)  # 不同的种子
    val_dataset = generate_dataset(
        num_instances=20,
        difficulty_distribution={'easy': 0.3, 'medium': 0.5, 'hard': 0.2},
        output_path='data/meeting_scheduling/val_dataset.json'
    )

    # 打印统计信息
    print("\n训练集统计:")
    print_dataset_statistics(train_dataset)

    print("\n\n验证集统计:")
    print_dataset_statistics(val_dataset)

    print("\n\n数据集生成完成！")
    print("训练集: data/meeting_scheduling/train_dataset.json")
    print("验证集: data/meeting_scheduling/val_dataset.json")


if __name__ == '__main__':
    main()
